package com.runa.monitor.platinterface.netservice.server;

import com.runa.monitor.platinterface.netservice.connect.Session;
import com.runa.monitor.platinterface.netservice.handler.ConcenChannelInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zhuj
 */
public class ConcentratorServer extends Server {

    private final Logger logger = LoggerFactory.getLogger(ConcentratorServer.class);

    private static final Map<String, ConcentratorServer> SERVERS = new HashMap<>();

    private String protocol;

    private int port;

    private EventLoopGroup bossGroup;

    private EventLoopGroup workGroup;

//    public static ConcentratorServer startServer(String host, int port, String protocol, String clientType) {
    public static ConcentratorServer startServer(int port, String protocol, boolean isTcp) {
//        String key = host+port+protocol+clientType;
        String key = port+protocol;
        ConcentratorServer server;
        synchronized (ConcentratorServer.class) {
            server = SERVERS.get(key);
            if (server == null) {
                server = new ConcentratorServer(port, protocol, isTcp);
                SERVERS.put(key, server);
            }
        }
        return server;
    }

    private ConcentratorServer(int port, String protocol, boolean isTcp) {
        this.port = port;
        this.protocol = protocol;
        bossGroup = new NioEventLoopGroup(1);
        workGroup = new NioEventLoopGroup();
        launch(isTcp);
    }

    private void launch(boolean isTcp) {
        if (isTcp) {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.SO_BACKLOG, 40960)
                    .childHandler(new ConcenChannelInitializer(protocol, true));
            try {
                bootstrap.bind(port).sync();
                logger.info("计量服务(TCP) ---  :{}", port);
            } catch (Exception e) {
                logger.error("监听启动失败(TCP) ---  :{}", port, e);
            }
        } else {
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(bossGroup)
                        .channel(NioDatagramChannel.class)
                        .handler(new ConcenChannelInitializer(protocol, false));
                bootstrap.bind(port).sync();
                logger.info("计量服务(UDP) ---  :{}", port);
            } catch (InterruptedException e) {
                logger.error("监听启动失败(UDP) ---  :{}", port, e);
            }
        }
    }

    @Override
    public void reConnect(Session session) {
    }

    @Override
    public boolean shutdown() {
        try {
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
            if (workGroup != null) {
                workGroup.shutdownGracefully();
            }
        } catch (Exception e) {
            logger.error("ConcentratorServer: {} close Error!", protocol);
            return false;
        }
        SERVERS.remove(this.port + this.protocol);
        logger.info("ConcentratorServer: {} close, listen port: {}",protocol, port);
        return true;
    }
}
